#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>

#include "imbus_internal.h"
#include "im_datalist.h"

/******** defines ********/
struct _IMDataList
{
    IMDataList      *next;
    IMQuark          id;
    IMPointer        data;
    IMDestroyFunc    destroy_func;
};

/******** functions *********/
void
im_datalist_init (IMDataList **datalist)
{
    _im_return_if_fail (datalist != 0);

    *datalist = 0;
}
void
im_datalist_clear (IMDataList **datalist)
{
    IMDataList *list;

    _im_return_if_fail (datalist != 0);

    list = *datalist;
    *datalist = 0;

    while (list) {
        IMDataList *prev;

        prev = list;
        list = list->next;

        if (prev->destroy_func)
            prev->destroy_func (prev->data);

        im_slice_delete (IMDataList, prev);
    }
}
IMSize
im_datalist_length (IMDataList **datalist)
{
    IMDataList *list;
    IMSize length;

    _im_return_val_if_fail (datalist != 0, 0);

    list = *datalist;
    length = 0;
    while (list) {
        length ++;
        list = list->next;
    }

    return length;
}
IMPointer
im_datalist_id_get_data (IMDataList **datalist, IMQuark key_id)
{
    IMPointer data = 0;

    _im_return_val_if_fail (datalist != 0, 0);

    if (key_id) {
        IMDataList *list;
        for (list = *datalist; list; list = list->next)
            if (list->id == key_id) {
                data = list->data;
                break;
            }
    }

    return data;
}
void
im_datalist_id_set_data_full (IMDataList **datalist, IMQuark key_id, IMPointer data, IMDestroyFunc destroy_func)
{
    IMDataList *list;

    _im_return_if_fail (datalist != 0);

    if (!data)
        _im_return_if_fail (destroy_func == 0);

    if (!key_id) {
        if (data)
            _im_return_if_fail (key_id > 0);

        return;
    }

    list = *datalist;

    if (!data) {
        IMDataList *prev;

        prev = 0;
        while (list) {
            if (list->id == key_id) {
                if (prev)
                    prev->next = list->next;
                else
                    *datalist = list->next;

                if (list->destroy_func)
                    list->destroy_func (list->data);

                im_slice_delete (IMDataList, list);

                return;
            }

            prev = list;
            list = list->next;
        }
    } else {
        while (list) {
            if (list->id == key_id) {
                if (list->destroy_func) {
                    IMDestroyFunc dfunc;
                    IMPointer ddata;

                    dfunc = list->destroy_func;
                    ddata = list->data;

                    list->data = data;
                    list->destroy_func = destroy_func;

                    dfunc (ddata);
                } else {
                    list->data = data;
                    list->destroy_func = destroy_func;
                }

                return;
            }
            list = list->next;
        }

        list = im_slice_new (IMDataList);
        list->next = *datalist;
        list->id = key_id;
        list->data = data;
        list->destroy_func = destroy_func;
        *datalist = list;
    }
}
IMPointer
im_datalist_id_steal (IMDataList **datalist, IMQuark key_id)
{
    IMDataList *list;
    IMDataList *prev;
    IMPointer   data;

    _im_return_val_if_fail (datalist != 0, 0);

    if (!key_id)
        return 0;

    prev = 0;
    list = *datalist;
    while (list) {
        if (list->id == key_id) {
            if (prev)
                prev->next = list->next;
            else
                *datalist = list->next;

            data = list->data;

            im_slice_delete (IMDataList, list);

            return data;
        }

        prev = list;
        list = list->next;
    }

    return 0;
}
IMBool
im_datalist_foreach (IMDataList **datalist, IMDataForeachFunc func, IMPointer user_data)
{
    IMDataList *list, *next;

    _im_return_val_if_fail (datalist != 0, FALSE);
    _im_return_val_if_fail (func != 0, FALSE);

    for (list = *datalist; list; list = next) {
        next = list->next;
        if (!func (list->id, list->data, user_data))
            return FALSE;
    }
    return TRUE;
}


/*
vi:ts=4:nowrap:ai:expandtab
*/
